#ifndef MOONLIGHT_OHOS_AUDIOPROCESSOR_H
#define MOONLIGHT_OHOS_AUDIOPROCESSOR_H

class XComponentBackend;
#include "PcmBufferSpan.h"
#include <Limelight.h>
#include <opus_multistream.h>
#include <ohaudio/native_audiostream_base.h>
#include <ohaudio/native_audiorenderer.h>
#include <mutex>
#include <condition_variable>
#include <list>

class AudioProcessor {
public:
    OpusMSDecoder *decoder;
    OH_AudioRenderer *renderer;

    explicit AudioProcessor(XComponentBackend *xcomp);
    virtual ~AudioProcessor();
private:
    AudioProcessor(const AudioProcessor &) = delete;
    AudioProcessor &operator=(const AudioProcessor &) = delete;

public:
    struct LimelightAudioCallbacks {
        static int init(int audioConfiguration, const POPUS_MULTISTREAM_CONFIGURATION opusConfig, void* context, int arFlags);
        static void start(void);
        static void stop(void);
        static void cleanup(void);
        static void decodeAndPlaySample(char* sampleData, int sampleLength);
        static inline const AUDIO_RENDERER_CALLBACKS callbacks = {
            .init = init,
            .start = start,
            .stop = stop,
            .cleanup = cleanup,
            .decodeAndPlaySample = decodeAndPlaySample,
        };
    };
    struct AudioRendererCallbacks {
        static int32_t OnWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t length);
        static int32_t OnStreamEvent(OH_AudioRenderer *renderer, void *userData, OH_AudioStream_Event event);
        static int32_t OnInterruptEvent(OH_AudioRenderer *renderer, void *userData, OH_AudioInterrupt_ForceType type, OH_AudioInterrupt_Hint hint);
        static int32_t OnError(OH_AudioRenderer *render, void *userData, OH_AudioStream_Result error);
        static inline const OH_AudioRenderer_Callbacks callbacks = {
            .OH_AudioRenderer_OnWriteData = OnWriteData,
            .OH_AudioRenderer_OnStreamEvent = OnStreamEvent,
            .OH_AudioRenderer_OnInterruptEvent = OnInterruptEvent,
            .OH_AudioRenderer_OnError = OnError,
        };
    };

private:
    static constexpr bool DEBUG = false;
    friend XComponentBackend;
    XComponentBackend &xcomp;
    struct {
        int audioConfiguration;
        OPUS_MULTISTREAM_CONFIGURATION opusConfig;
        void *context;
        int arFlags;
    } limelightParams;
    std::mutex renderMtx;
    std::condition_variable renderReadyCond;
    std::list<PcmBufferSpan> renderQueue;
};

#define INIT_AUDIO_PROCESSOR_SELF_OR_ELSE(otherwise) \
    ENSURE_GSMGR_OR_ELSE(otherwise); \
    if (GameStreamManager::xcomponentBackend->audioProcessor == nullptr) { \
        OH_LOG_FATAL(LOG_APP, "AudioProcessor is not functional at the time of this %{public}s invocation", __PRETTY_FUNCTION__); \
        otherwise; \
    } \
    auto &self = *GameStreamManager::xcomponentBackend->audioProcessor;

#endif //MOONLIGHT_OHOS_AUDIOPROCESSOR_H
